package com.github.phoenics.teacher.itheima.netty.protocol;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * @author Phoenics Chow
 * on 2020年02月21日
 */
public class HttpFileServer {
    private static final String DEFAULT_URL = "/test/netty/";

    public void run(final int port, final String url) throws Exception {
        //配置服务端的NIO线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //netty用于启动NIO服务端的辅助启动类
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChildChannelHandler(url));
            //绑定IO事件的处理类，记录日志、对消息进行编解码操作
            //绑定端口，同步等待成功
            //ChannelFuture f = b.bind("192.168.63.42", port).sync();
            ChannelFuture f = b.bind( port).sync();
            System.out.println("HTTP 文件服务器启动， 网址是 ： http://127.0.0.1:" + port + url);
            //等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            //优雅退出，释放资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        private final String url;
        ChildChannelHandler(String url) {
            this.url=url;
        }
        @Override
        protected void initChannel(SocketChannel arg0) throws Exception {
            ChannelPipeline pipeline = arg0.pipeline();
            //HttpServerCodec是netty中非常重要的一个类,用来设置http的编码和解码，
            pipeline.addLast("httpServerCodec", new HttpServerCodec())
                    // http 消息聚合器  512*1024为接收的最大contentlength
                    //用于HTTP消息聚合，将多个消息转换为单一的FullHttpRequest和FullHttpResponse。
                    //因为HttpServerCodec解码器在每个HTTP消息中会生产多个对象：
                    // HttpRequest、HttpResponse、HttpContent、LastHttpContent。
                    .addLast("httpAggregator", new HttpObjectAggregator(512 * 1024))
                    // 支持异步发送大的码流(大的文件传输),但不占用过多的内存，防止java内存溢出
                    .addLast("http-chunked", new ChunkedWriteHandler())
                    .addLast(new HttpFileServerHandler(url));

        }
    }

    public static void main(String[] args) throws Exception {
        int port = 9090;
        if (args != null && args.length > 0) {
            try {
                port = Integer.valueOf(args[0]);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String url = DEFAULT_URL;
        if (args.length > 1) {
            url = args[1];
        }
        new HttpFileServer().run(port, url);
    }
}

